package cn.wolfcode.rbac.service.impl;

import cn.wolfcode.rbac.common.RedisKeyPrefix;
import cn.wolfcode.rbac.domain.Employee;
import cn.wolfcode.rbac.mapper.EmployeeMapper;
import cn.wolfcode.rbac.mapper.PermissionMapper;
import cn.wolfcode.rbac.service.ILoginService;
import cn.wolfcode.rbac.service.IRoleService;
import cn.wolfcode.rbac.springsecurity.detail.EmployeeDetails;
import cn.wolfcode.rbac.utils.JwtUtils;
import cn.wolfcode.rbac.utils.RedisUtils;
import cn.wolfcode.rbac.utils.VerifyCodeUtil;
import cn.wolfcode.rbac.web.exception.BusinessException;
import cn.wolfcode.rbac.web.vo.LoginInfoVo;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;
import java.util.Set;
import java.util.UUID;

import static cn.wolfcode.rbac.common.RedisKeyPrefix.*;

@Service
@Transactional
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private EmployeeMapper employeeMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private JwtUtils jwtUtils;


    @Override
    public Map<String, String> generator() {
        //动态生成验证码图片
        Map<String, String> map = VerifyCodeUtil.generateVerifyCode();
        String code = map.get("code");
        System.out.println("code = " + code);
        String uuid = map.get("uuid");
        //给验证码设置过期时间
        redisUtils.set(VERIFY_CODE_PREFIX + uuid, code, EXPRE_TIME);
        //删除验证码
        map.remove("code");
        //返回验证码图片
        return map;
    }

    @Override
    public String login(LoginInfoVo loginInfoVo) {
        //1.校验验证码
        String code = loginInfoVo.getCode();
        //获取redis的code进行校验
        String redisCode = redisUtils.get(VERIFY_CODE_PREFIX + loginInfoVo.getUuid());
        if (redisCode == null) {
            //验证码过期,请重新获取
            throw new BusinessException("验证码过期,请重新获取");
        }
        if (!VerifyCodeUtil.verification(redisCode, code, true)) {
            throw new BusinessException("验证码不正确");
        }

        //2.调用认证器,如果验证错误，则抛出异常
        Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginInfoVo.getUsername(), loginInfoVo.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        EmployeeDetails employeeDetails = (EmployeeDetails) authenticate.getPrincipal();
        Employee employee = employeeDetails.getEmployee();
        //生成uuid,把uuid封装成token,并把token作为key,把employee信息存入redis中
        String uuid = UUID.randomUUID().toString();
        String token = jwtUtils.createToken("uuid", uuid);

        //登录成功从redis中删除code验证码
        redisUtils.del(VERIFY_CODE_PREFIX + loginInfoVo.getUuid());
        //3.校验成功，employee信息存入redis中，用于权限校验时，从redis中获取是否登录
        //对employee进行序列化操作
        redisUtils.set(LOGIN_EMPLOYEE_PREFIX + uuid, JSON.toJSONString(employee));

        //4.再把该用户的权限也存入redis中，待下次访问时候，从redis中获取判断是否有权限
        //判断员工是超级管理员，如果不是超级管理员，则根据id查询权限，然后存到redis中，提升性能在下次访问从redis中取
//        if (!employee.getAdmin()) {
//            //根据员工id查询所有的权限
//            Long employeeId = employee.getId();
//            Set<String> expressions = permissionMapper.queryExpressionByEmployeeId(employeeId);
//
//            //如果有权限就保存到redis中
//            if (!expressions.isEmpty()) {
//                redisUtils.set(EMPLOYEE_EXPRESSION_PREFIX + uuid, JSON.toJSONString(expressions));
//            }
//        }
        return token;
    }

    @Override
    public void logout(String id) {
        //根据员工id，从redis中删除员工信息和权限
        //1.删除redis中的员工信息
        redisUtils.del(LOGIN_EMPLOYEE_PREFIX + id);

        //2.删除redis中的员工信息的所有权限
        redisUtils.del(EMPLOYEE_EXPRESSION_PREFIX + id);
    }
}
